﻿#region Using statements
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.IO;
#endregion


namespace SmartFrequency.SoundCapture
{
    class SoundCapturePlay : Language
    {
        #region Private variables
        private WaveIn wi = null;
        private WaveOut wo = null;

        enum OpState
        {
            STOPING = 0,
            PLAYING,
            RECORDING,
            PAUSING
        };

        private OpState OperationState;

        // Holds number of recorded items
        private int RecordCount = 0;

        // Used to save filename
        private String RecordName = null, PlayFile = null;
        #endregion

        #region Public variables
        public struct RecordingParameters
        {
            private int m_sampling, m_channelno, m_bitspersample, m_duration, m_buffersize;
            public int SamplingRate
            {
                get { return m_sampling; }
                set { m_sampling = value; }
            }

            public int ChannelNo
            {
                get { return m_channelno; }
                set { m_channelno = value; }
            }

            public int BitsPerSample
            {
                get { return m_bitspersample; }
                set { m_bitspersample = value; }
            }

            public int Duration
            {
                get { return m_duration; }
                set { m_duration = value; }
            }

            public int BufferSize
            {
                get { return m_buffersize; }
                set { m_buffersize = value; }
            }
        }

        public struct PlayingParameters 
        {
            private int m_buffersize;
            private ushort m_leftvolume, m_rightvolume;

            public int BufferSize
            {
                get { return m_buffersize; }
                set { m_buffersize = value; }
            }

            public int LeftVolume
            {
                get { return m_leftvolume; }
                set { m_leftvolume = (ushort) value; }
            }

            public int RightVolume
            {
                get { return m_rightvolume; }
                set { m_rightvolume = (ushort) value; }
            }

        }
            
            
        public PlayingParameters PlayParams;
        public RecordingParameters RecordParams;
        #endregion

        #region Public functions
        public SoundCapturePlay():base(Language_e.TR)
        {
            RecordParams.SamplingRate = 22050;
            RecordParams.BitsPerSample = 16;
            RecordParams.ChannelNo = 1;
            RecordParams.Duration = 300000;
            RecordParams.BufferSize = 16 * 22050;

            PlayParams.BufferSize = 16 * 22050;
            PlayParams.LeftVolume = (ushort)0xFFFF;
            PlayParams.RightVolume = (ushort)0xFFFF;
        }

        public int RecordInit()
        {
            // Input class initilization
            if (wi != null)
                wi.Dispose();

            try
            {
                wi = new WaveIn(RecordParams.SamplingRate, RecordParams.ChannelNo, RecordParams.BitsPerSample);
                int numInputDevices;

                if ((numInputDevices = (int)wi.NumDevices()) < 1)
                {
                    MessageBox.Show(ErrMsgToString(FailureMsg_e.ERR_SOUNDDEVICE));
                    return -1;
                }

                if (Wave.MMSYSERR.NOERROR != wi.Preload(RecordParams.Duration, RecordParams.BufferSize))
                {
                    MessageBox.Show(ErrMsgToString(FailureMsg_e.ERR_BUFFERS));
                    return -1;
                }
            }
            catch
            {
                return -1;
            }

            return 1;
        }

        public int RecordStart()
        {
            if (Wave.MMSYSERR.NOERROR != wi.Start())
            {
                MessageBox.Show(ErrMsgToString(FailureMsg_e.ERR_STARTRECORDING));
                return -1;
            }

            return 1;
        }

        public int RecordStop()
        {
            try
            {
                if ((RecordName == null) || (wi == null))
                    return -1;

                wi.Stop();

                //MessageBox.Show("Saving file test.wav");
                if (Wave.MMSYSERR.NOERROR != wi.Save(RecordName))
                {
                    MessageBox.Show(ErrMsgToString(FailureMsg_e.ERR_SAVE));
                    return -1;
                }

                //wi.Dispose();

                if (Wave.MMSYSERR.NOERROR != wi.Preload(RecordParams.Duration, RecordParams.BufferSize))
                {
                    MessageBox.Show(ErrMsgToString(FailureMsg_e.ERR_BUFFERS));
                    return -1;
                }
            }
            catch
            {
                MessageBox.Show(ErrMsgToString(FailureMsg_e.ERR_UNKNOWN));
                return -1;
            }

            return 1;
        }

        public string RecordFileName()
        {
            StringBuilder str = new StringBuilder();
            do
            {
                str.AppendFormat("Record{0}.wav", RecordCount);
                //RecordName = System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase;
                RecordName = "\\My Documents\\My Music\\";
                //RecordName = Path.GetDirectoryName(RecordName);
                RecordName = Path.Combine(RecordName, str.ToString());
                str.Remove(0, str.Length);
                RecordCount++;
            } while (File.Exists(RecordName) == true);

            PlayFileName(RecordName);

            return RecordName;
        }

        public bool RecordStatus()
        {
            return wi.Done();
        }

        public void RecordDestroy()
        {
            if(wi != null)
                wi.Dispose();
        }

        public int PlayInit()
        {
            // Output class initilization
            wo = new WaveOut();
            uint numOutputDevices = wo.NumDevices();
            if (numOutputDevices < 1)
            {
                MessageBox.Show(ErrMsgToString(FailureMsg_e.ERR_NODEVICE));
                return -1;
            }

            return 1;
        }

        public int PlayMemoryStart()
        {
            if (wo == null)
                return -1;

            if (Wave.MMSYSERR.NOERROR != wo.PlayFromMemory(PlayParams.BufferSize, (ushort)PlayParams.LeftVolume, (ushort)PlayParams.RightVolume))
            {
                //MessageBox.Show(ErrMsgToString(FailureMsg_e.ERR_STARTPLAYING));
                return -1;
            }

            return 1;
        }

        public int PlayStart()
        {
            if ((wo == null) || (PlayFile == null))
                return -1;

            if (Wave.MMSYSERR.NOERROR != wo.PlayFromFile(PlayFile, PlayParams.BufferSize, (ushort)PlayParams.LeftVolume, (ushort)PlayParams.RightVolume))
            {
                MessageBox.Show(ErrMsgToString(FailureMsg_e.ERR_STARTPLAYING));
                return -1;
            }

            uint soundLength = wo.Milliseconds();
            return 1;
        }

        public int PlayPause()
        {
            if (wo == null)
                return -1;

            wo.Pause();
            //wo.Dispose();
            return 1;
        }

        public int PlayStop()
        {
            if (wo == null)
                return -1;

            //wo.Pause();
            wo.Stop();
            //wo.Dispose();
            return 1;
        }

        public int PlayResume()
        {
            if (wo == null)
                return -1;

            wo.Resume();
            return 1;
        }

        public uint PlayFileLength()
        {
            if (wo == null)
                return 0;

            return wo.GetFileLength(PlayFile);
        }

        public void PlayDestroy()
        {
            if (wo != null)
                wo.Dispose();
        }

        public int PlayTime()
        {
            if (wo == null)
                return 0;

            return (int)wo.Milliseconds();
        }

        public bool PlayStatus()
        {
            // TODO : This function is not understanding EOF, so can not determinates whether stream is finished or not.
            //        Highly advise not to use
            return wo.Done();
        }

        public string PlayFileName(string name)
        {
            if (name != "")
                PlayFile = name;

            return PlayFile;
        }

        public void Dispose()
        {
            PlayDestroy();
            RecordDestroy();
        }
        #endregion
    }
}
